#region Copyright Notice
// 
// 
//  
//  Copyright (c) 2009-2011 Anindya Chatterjee
//  
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//      http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
// 
// 
#endregion
using System;
using System.ComponentModel;
using System.Linq.Expressions;

namespace AbstractClass.Extensions
{
    /// <summary>
    /// Provides a set of extension methods for <see cref="INotifyPropertyChanged"/>.
    /// </summary>
    public static class NotifyPropertyChangedExtensions
    {
        #region | Code Taken from Mannex Library |

        /// <summary>
        ///   Subscribes to <see cref="INotifyPropertyChanged.PropertyChanged"/>
        ///   event of the source object and calls <paramref name="handler"/> only
        ///   when the property identified by <paramref name="expression"/>
        ///   has changed.
        /// </summary>
        /// <returns>
        ///   Returns the <see cref="PropertyChangedEventHandler"/> object that
        ///   can be used for unsubscribing.
        /// </returns>
        /// <exception cref="ArgumentException">
        ///   Thrown if <paramref name="expression"/> does not represent a simple
        ///   property/field access type of expression (see <see cref="MemberExpression"/>).
        /// </exception>
        /// <remarks>
        ///   If <paramref name="expression"/> is <c>null</c> or empty then
        ///   <paramref name="handler"/> is called when any property changes.
        /// </remarks>
        public static PropertyChangedEventHandler OnPropertyChanged<T, TValue>(this T source,
                                                                               Expression<Func<T, TValue>> expression,
                                                                               PropertyChangedEventHandler handler)
            where T : INotifyPropertyChanged
        {
            string propertyName = null;

            if (expression != null)
            {
                var member = expression.Body as MemberExpression;
                member.ThrowIfNull("expression");
// ReSharper disable PossibleNullReferenceException
                propertyName = member.Member.Name;
// ReSharper restore PossibleNullReferenceException
            }

            return OnPropertyChanged(source, propertyName, handler);
        }

        private static PropertyChangedEventHandler OnPropertyChanged(this INotifyPropertyChanged source,
                                                                     string propertyName,
                                                                     PropertyChangedEventHandler handler)
        {
            source.ThrowIfNull("source");
            handler.ThrowIfNull("handler");

            PropertyChangedEventHandler onChanged = (sender, args) =>
                                                        {
                                                            if (string.IsNullOrEmpty(propertyName)
                                                                ||
                                                                args.PropertyName.Equals(propertyName,
                                                                                         StringComparison.
                                                                                             OrdinalIgnoreCase))
                                                                handler(sender, args);
                                                        };

            source.PropertyChanged += onChanged;
            return onChanged;
        }

        #endregion
    }
}